package com.dayu.gulimall.order.config;

import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.connection.CorrelationData;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter;
import org.springframework.amqp.support.converter.MessageConverter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.annotation.PostConstruct;

/**
 * @author dayu
 * @email dayu@foxmail.com
 * @date 2021/4/15:14:34
 * @Description RabbitMQ消息转换默认用JSON格式发送，当发送对象的时候，自动将对象转化为JSON
 */
@Configuration
public class MyMessageConverter {
    @Autowired
    RabbitTemplate rabbitTemplate;

    @Bean
    public MessageConverter messageConverter() {
        return new Jackson2JsonMessageConverter();
    }


    /**
     * MyMessageConverterd对象创建完成以后，执行这个方法
     * 定制RabbitTemplate
     * 1、服务端收到消息就回调
     *      1、spring.rabbitmq.publisher-returns=true
     *      2、设置setConfirmCallback
     * 2、消息正确抵达队列进行回调
     *      #发送端消息抵达的确认
     *      1、spring.rabbitmq.publisher-confirm-type=correlated
     *      #如果抵达队列，就优先回调这个，以异步的方式 returnconfirm
     *         spring.rabbitmq.template.mandatory=true
     *      2、设置确认回调setReturnCallback
     *  3、消费端确认（保证每个消息被正确消费后，才可以broker删除这个消息）
     *      1、默认是自动确认机制，客户端只要接守到消息就自动确认，服务器端就会移除这个消息
     *      问题：
     *          消息丢失问题
     *       2、如何签收：
     *          改为手动签收：客户端，消息手动ack模式
     *          spring.rabbitmq.listener.simple.acknowledge-mode=manual
     *
     *
     */
    @PostConstruct
    public void initRabbitTemplate() {
        //设置确认回调
        rabbitTemplate.setConfirmCallback(new RabbitTemplate.ConfirmCallback() {
            /**
             * 1、只要消息抵达Broker就ack=true
             * @param correlationData 当前消息的唯一关联数据，这是消息的唯一id
             * @param ack 消息是否成功抵达消息队列
             * @param cause  失败的原因
             */
            @Override
            public void confirm(CorrelationData correlationData, boolean ack, String cause) {
                System.out.println("setConfirmCallback correlationData=[" + correlationData + "],ack=[" + ack + "],cause=[" + cause + "]");
            }
        });

        //设置消息抵达队列的确认回调，只要消息没有投递给指定的队列，就触发这个机制
        rabbitTemplate.setReturnCallback(new RabbitTemplate.ReturnCallback() {
            /**
             * @param message 消息的详细信息
             * @param replyCode 回复的状态码
             * @param replyText 回复的文本内容
             * @param exchange 发送消息使用的路由器
             * @param routingKey 这个消息的路由键
             */
            @Override
            public void returnedMessage(Message message, int replyCode, String replyText, String exchange, String routingKey) {
                System.out.println("setReturnCallback message:[" + message + "],replyCode:[" + replyCode + "],replyText:[" + replyText + "]," +
                        "exchange:[" + exchange + "],routingKey:[" + routingKey + "]");
            }
        });

    }
}
